using ColorFillGame.Application.Commands.Game;
using ColorFillGame.Application.Commands;
using ColorFillGame.Application.Queries.Game;
using ColorFillGame.Application.Queries.Player;
using MediatR;
using Microsoft.AspNetCore.SignalR;

namespace ColorFillGame.API.Hubs;

public class GameHub : Hub
{
    private readonly IMediator _mediator;
    private const string GameGroupPrefix = "game_";

    public GameHub(IMediator mediator)
    {
        _mediator = mediator;
    }

    public override async Task OnDisconnectedAsync(Exception? exception)
    {
        // 当玩家断开连接时，自动离开游戏
        var player = await _mediator.Send(new GetPlayerByConnectionIdQuery(Context.ConnectionId));
        if (player != null)
        {
            await LeaveGame(player.GameId, player.Id);
        }

        await base.OnDisconnectedAsync(exception);
    }

    public async Task<Guid> CreateGame(string gameName, int gridSize, int maxPlayers, string customGameId = null)
    {
        var command = new CreateGameCommand(gameName, gridSize, maxPlayers, customGameId);
        var gameId = await _mediator.Send(command);
        
        // 自动将创建者加入游戏
        var playerName = gameName + "_Creator";
        var playerId = await JoinGame(gameId, playerName);
        
        // 向创建者发送游戏创建成功的消息
        await Clients.Caller.SendAsync("GameCreated", gameId);
        
        return gameId;
    }

    public async Task<Guid> JoinGame(Guid gameId, string playerName)
    {
        var command = new JoinGameCommand(gameId, playerName, Context.ConnectionId);
        var playerId = await _mediator.Send(command);

        // 将玩家添加到游戏组
        await Groups.AddToGroupAsync(Context.ConnectionId, $"{GameGroupPrefix}{gameId}");

        // 先等待一小段时间，确保玩家完全加入组
        await Task.Delay(100);

        // 获取游戏信息并广播给游戏中的所有玩家
        var gameDto = await _mediator.Send(new GetGameQuery(gameId));
        await Clients.Group($"{GameGroupPrefix}{gameId}").SendAsync("GameUpdated", gameDto);

        return playerId;
    }

    public async Task LeaveGame(Guid gameId, Guid playerId)
    {
        var command = new LeaveGameCommand(gameId, playerId);
        await _mediator.Send(command);

        // 将玩家从游戏组中移除
        await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"{GameGroupPrefix}{gameId}");

        // 获取游戏信息并广播给游戏中的所有玩家
        var gameDto = await _mediator.Send(new GetGameQuery(gameId));
        await Clients.Group($"{GameGroupPrefix}{gameId}").SendAsync("GameUpdated", gameDto);
    }

    public async Task StartGame(Guid gameId, Guid playerId)
    {
        var command = new StartGameCommand(gameId, playerId);
        await _mediator.Send(command);

        // 获取游戏信息并广播给游戏中的所有玩家
        var gameDto = await _mediator.Send(new GetGameQuery(gameId));
        await Clients.Group($"{GameGroupPrefix}{gameId}").SendAsync("GameStarted", gameDto);
    }

    public async Task PerformPaintAction(Guid gameId, Guid playerId, int x, int y)
    {
        try
        {
            Console.WriteLine($"收到PerformPaintAction调用: GameId={gameId}, PlayerId={playerId}, X={x}, Y={y}");
            
            // 验证参数有效性
            if (gameId == Guid.Empty)
            {
                throw new ArgumentException("GameId cannot be empty");
            }
            
            if (playerId == Guid.Empty)
            {
                throw new ArgumentException("PlayerId cannot be empty");
            }
            
            var command = new PaintActionCommand(gameId, playerId, x, y);
            Console.WriteLine("创建PaintActionCommand成功");
            
            await _mediator.Send(command);
            Console.WriteLine("成功执行PaintActionCommand");

            // 获取游戏信息并广播给游戏中的所有玩家
            var gameDto = await _mediator.Send(new GetGameQuery(gameId));
            await Clients.Group($"{GameGroupPrefix}{gameId}").SendAsync("GameUpdated", gameDto);

            // 获取执行涂色操作的玩家
            var player = gameDto.Players.FirstOrDefault(p => p.Id == playerId);
            
            // 广播涂色操作，并包含完整信息
            await Clients.Group($"{GameGroupPrefix}{gameId}").SendAsync("PaintActionPerformed", new 
            {
                GameId = gameId,
                PlayerId = playerId,
                PlayerName = player?.Name ?? "未知玩家",
                X = x,
                Y = y,
                Color = player?.ColorCode ?? "#000000", // 使用玩家的实际颜色代码
                Timestamp = DateTime.UtcNow
            });
            
            Console.WriteLine($"广播涂色操作: PlayerId={playerId}, PlayerName={player?.Name}, Color={player?.ColorCode}, Position=({x},{y})");
        }
        catch (ColorFillGame.Domain.Exceptions.InvalidPositionException ex)
        {
            Console.WriteLine($"位置无效错误: {ex.Message}");
            Console.WriteLine(ex.StackTrace);
            throw new HubException("位置无效: " + ex.Message + "。请确保坐标在游戏网格范围内。");
        }
        catch (ColorFillGame.Domain.Exceptions.DomainException ex)
        {
            Console.WriteLine($"游戏逻辑错误: {ex.Message}");
            Console.WriteLine(ex.StackTrace);
            throw new HubException("游戏错误: " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"PerformPaintAction执行出错: {ex.Message}");
            Console.WriteLine(ex.StackTrace);
            throw new HubException("执行涂色操作时发生错误，请稍后再试。");
        }
    }

    public async Task<List<ActiveGameDto>> GetActiveGames()
    {
        return await _mediator.Send(new GetActiveGamesQuery());
    }

    // 处理玩家准备状态变更
    public async Task SetPlayerReady(Guid gameId, Guid playerId, bool ready)
    {
        // 先获取当前玩家颜色
        var gameBefore = await _mediator.Send(new GetGameQuery(gameId));
        var currentPlayer = gameBefore.Players.FirstOrDefault(p => p.Id == playerId);
        var currentColor = currentPlayer?.ColorCode;

        // 更新准备状态
        var command = new SetPlayerReadyCommand(gameId, playerId, ready);
        await _mediator.Send(command);

        // 获取更新后的游戏数据
        var gameAfter = await _mediator.Send(new GetGameQuery(gameId));
        
        // 确保颜色不变
        var updatedPlayer = gameAfter.Players.FirstOrDefault(p => p.Id == playerId);
        if (updatedPlayer != null && currentColor != null)
        {
            updatedPlayer.ColorCode = currentColor;
        }

        await Clients.Group($"{GameGroupPrefix}{gameId}").SendAsync("GameUpdated", gameAfter);
    }
    
    // 处理玩家颜色设置
    public async Task SetPlayerColor(Guid gameId, Guid playerId, string color)
    {
        try
        {
            Console.WriteLine($"收到SetPlayerColor调用: GameId={gameId}, PlayerId={playerId}, Color={color}");
            
            // 验证参数有效性
            if (gameId == Guid.Empty)
            {
                throw new ArgumentException("GameId cannot be empty");
            }
            
            if (playerId == Guid.Empty)
            {
                throw new ArgumentException("PlayerId cannot be empty");
            }
            
            if (string.IsNullOrEmpty(color))
            {
                throw new ArgumentException("Color cannot be empty");
            }
            
            var command = new SetPlayerColorCommand(gameId, playerId, color);
            await _mediator.Send(command);
            Console.WriteLine("成功执行SetPlayerColorCommand");

            // 获取游戏信息并广播给游戏中的所有玩家
            var gameDto = await _mediator.Send(new GetGameQuery(gameId));
            await Clients.Group($"{GameGroupPrefix}{gameId}").SendAsync("GameUpdated", gameDto);
        }
        catch (ColorFillGame.Domain.Exceptions.DomainException ex)
        {
            Console.WriteLine($"游戏逻辑错误: {ex.Message}");
            throw new HubException("游戏错误: " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"SetPlayerColor执行出错: {ex.Message}");
            throw new HubException("设置玩家颜色时发生错误，请稍后再试。");
        }
    }
}